package edu.up.firesawakening;

import java.io.Serializable;
import java.util.Vector;

/**
 * Represents a single unit
 * 
 * @author Alex Hanemann
 * @author Matt Delaney
 * @version 7 November 2012
 */
public abstract class Unit implements Serializable, Cloneable {

	/**
	 * Serial ID
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * all possible actions this unit could take this turn
	 */
	protected Vector<TacticsAction> m_actions;

	/**
	 * indicates when the last actions update was. Used to avoid unnecessary
	 * recalculation
	 */
	protected int m_turnCode;

	/**
	 * Unit health
	 */
	protected int m_health;

	/**
	 * Unit max health
	 */
	protected int m_maxHealth;

	/**
	 * Unit attack power
	 */
	protected int m_atkPow;

	/**
	 * Unit defense
	 */
	protected int m_armor;

	/**
	 * Distance unit can move
	 */
	protected int m_moveRange;

	/**
	 * Range at which the unit can attack (Default: 1)
	 */
	protected int m_attackRange;

	/**
	 * Player who can move the unit
	 */
	protected int m_player;

	/**
	 * Number of spaces the unit can still move this turn.
	 */
	protected int m_movesLeft;

	/**
	 * Indicates whether or not the unit has attacked this turn
	 */
	protected boolean m_attackAvailable = true;

	/**
	 * @return the unit's max health value
	 */
	public int getMaxHealth() {
		return m_maxHealth;
	}

	/**
	 * @param moves
	 *            the number of moves left
	 */
	public void setMovesLeft(int moves) {
		m_movesLeft = moves;
	}

	/**
	 * @return the number of spaces this unit can still move this turn
	 */
	public int getMovesLeft() {
		return m_movesLeft;
	}

	/**
	 * @return this unit's owner
	 */
	public int getOwner() {
		return m_player;
	}

	/**
	 * @return this unit's move range
	 */
	public int getMoveRange() {
		return m_moveRange;
	}

	/**
	 * @return this unit's armor rating
	 */
	public int getArmor() {
		return m_armor;
	}

	/**
	 * @return this unit's attack power
	 */
	public int getAtkPow() {
		return m_atkPow;
	}

	/**
	 * @return this unit's current health
	 */
	public int getHealth() {
		return m_health;
	}

	/**
	 * @return whether or not this unit is still alive
	 */
	public boolean isAlive() {
		return m_health > 0;
	}

	/**
	 * @return the attack range of this unit
	 */
	public int getAttackRange() {
		return m_attackRange;
	}

	/**
	 * @param action
	 *            an action to add
	 */
	public void addAction(TacticsAction action) {
		m_actions.add(action);
	}

	/**
	 * @return the list of actions this unit can take
	 */
	public Vector<TacticsAction> getActions() {
		return m_actions;
	}

	/**
	 * Clears out the actions list for this unit
	 */
	public void clearActions() {
		m_actions.clear();
	}

	/**
	 * Launches an attack
	 * 
	 * @param targetUnit
	 *            the unit to attack
	 */
	public void attack(Unit targetUnit) {
		targetUnit.recieveAttack(m_atkPow);
		m_attackAvailable = false;
	}

	/**
	 * @return whether or not the unit has attacked this turn
	 */
	public boolean hasAttackAvailable() {
		return m_attackAvailable;
	}

	/**
	 * Allows unit to attack again next turn
	 * 
	 * @param attack
	 *            the unit has attacked
	 */
	public void setAttackAvailable(boolean attack) {
		m_attackAvailable = attack;
	}

	/**
	 * Handles incoming damage to this unit
	 * 
	 * @param damage
	 *            the attack power of the attacking unit
	 */
	public void recieveAttack(int damage) {
		damage -= m_armor;
		m_health -= (damage > 0 ? damage : 0);

		if (m_health < 0)
			m_health = 0;
	}

	/**
	 * Don't use this, only here for making new Castles.
	 * 
	 * @param health
	 *            new health to set
	 */
	protected void setHealth(int health) {
		m_health = health;
	}

	/**
	 * Constructs a unit with the specified attributes.
	 * 
	 * @param healthIn
	 *            starting health
	 * @param damageIn
	 *            attack power
	 * @param armorIn
	 *            armor rating
	 * @param moveRangeIn
	 *            move range
	 * @param attackRangeIn
	 *            attack range
	 * @param playerIn
	 *            owner of this unit
	 */
	public Unit(int healthIn, int damageIn, int armorIn, int moveRangeIn,
			int attackRangeIn, int playerIn) {
		m_health = m_maxHealth = healthIn;
		m_atkPow = damageIn;
		m_armor = armorIn;
		m_moveRange = moveRangeIn;
		m_attackRange = attackRangeIn;
		m_player = playerIn;
		m_movesLeft = m_moveRange;
		m_actions = new Vector<TacticsAction>();
	}

	public abstract Unit clone();
}
